package pers.zb.cloud.oauth.support;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import pers.zb.cloud.oauth.service.UserService;
import pers.zb.cloud.oauth.util.HttpClientUtil;
import pers.zb.cloud.oauth.vo.JsonResult;
import pers.zb.cloud.oauth.vo.UserAuthoritiesInfoVo;
import pers.zb.cloud.oauth.vo.UserStatus;

import java.util.*;

/**
 * 获取用户信息 业务处理
 */
@Service
public class CustomizeUserDetailsService implements UserDetailsService {

    @Autowired
    private UserService userService;

    //Oauth认证系统的获取token的URL
    @Value("${oauth.system.url}")
    private String oauthTokenUrl;

    //用户服务的clientId
    @Value("${oauth.user-service.client-id}")
    private String userServiceSystemClientId;

    //用户服务的clientSecret
    @Value("${oauth.user-service.client-secret}")
    private String userServiceSystemClientSecret;


    /**
     * 根据用户名获取用户信息，包含用户角色以及权限。
     *
     *      Oauth认证系统在登录的时候，最终会调用到此方法来获取用户信息
     *      用户信息是从 sea-cloud-service-user服务中查询获取的，通过feign远程调用实现，具体代码请查看 userService.getUserByName()方法
     */
    @Override
    public UserDetails loadUserByUsername(String userName) {
        //获取用于请求认证的access_token - 会拿这个token凭证请求用户服务（sea-cloud-service-user）获取用户信息
        String accessToken = getAccessToken(userServiceSystemClientId, userServiceSystemClientSecret);

        //用户服务系统（sea-cloud-service-user）返回的用户相关信息，包含拥有的角色以及权限
        String userServiceResult;
        try{
            userServiceResult = userService.getUserByName(userName,accessToken);
        }catch (Exception e){
            throw new AuthenticationServiceException("登录出现异常，请稍后重试");
        }

        //检查用户登录账户是否正常
        UserAuthoritiesInfoVo userAuthoritiesInfoVo = checkUser(userName,userServiceResult);

        //加载用户的权限
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        List<String> PermissionCodeList = userAuthoritiesInfoVo.getPermissionCode();
        for (String permissionCode :PermissionCodeList ) {
            authorities.add(new SimpleGrantedAuthority(permissionCode));
        }

        //返回认证用户的信息
        return new User(userAuthoritiesInfoVo.getUserName(), userAuthoritiesInfoVo.getPassword(), authorities);
    }


    /**
     * 检查用户登录账户是否正常
     * @param userName
     * @param userInfo
     * @return
     */
    public UserAuthoritiesInfoVo checkUser(String userName, String userInfo){
        if(StringUtils.isEmpty(userInfo)){
            throw new AuthenticationServiceException("登录出现异常，请稍后重试");
        }

        JsonResult jsonResult;
        try {
            jsonResult = JSONObject.parseObject(userInfo,JsonResult.class);
        }catch (Exception e){
            throw new AuthenticationServiceException("登录出现异常，请稍后重试");
        }

        if(jsonResult.getResult() == null){
            throw new BadCredentialsException("账户 " + userName + " 不存在");
        }

        UserAuthoritiesInfoVo userAuthoritiesInfoVo;
        try{
            userAuthoritiesInfoVo = JSONObject.parseObject(JSONObject.toJSONString(jsonResult.getResult()),UserAuthoritiesInfoVo.class);
        }catch (Exception e){
            throw new BadCredentialsException("无法获取账户 " + userName + " 的信息，请检查登录账户信息是否正确");
        }

        if(userAuthoritiesInfoVo.getStatus() == UserStatus.LOCKING){ //锁定状态
            throw new LockedException("登录账户 " + userName + " 已被锁定，无法登录");
        }
        if(userAuthoritiesInfoVo.getStatus() == UserStatus.DISABLE){ //禁用状态
            throw new DisabledException("登录账户 " + userName + " 已被禁用，无法登录");
        }
        return userAuthoritiesInfoVo;
    }


    /**
     * 获取用于请求认证的access_token
     */
    public String getAccessToken(String clientId,String clientSecret){
        try{
            //获取客户端的认证授权信息
            String userServiceClientEncoder = getClientAuthorizationEncoder(clientId,clientSecret);

            //参数map
            Map<String, String> parameterMap = new HashMap<String, String>();
            parameterMap.put("grant_type", "client_credentials");

            //Header参数Map
            Map<String, String> headerMap = new HashMap<String, String>();
            headerMap.put("Authorization","Basic " + userServiceClientEncoder);

            //请求oauth授权服务（也就是当前系统服务），获取token
            byte[] b = HttpClientUtil.doPost(oauthTokenUrl,headerMap, parameterMap,"UTF-8");
            Map<String,Object> map =  JSONObject.parseObject(new String(b),Map.class);

            String token = (String) map.get("access_token");
            return token;
        }catch (Exception e){
            throw new AuthenticationServiceException("登录出现异常，请稍后重试");
        }
    }

    /**
     * 获取客户端的认证授权信息
     * @param clientId
     * @param clientSecret
     * @return
     */
    public static String getClientAuthorizationEncoder(String clientId,String clientSecret){
        return new String(Base64.getEncoder().encode(new String(clientId + ":" + clientSecret).getBytes()));
    }
}
